package cn.kgc.util.exception;

import cn.kgc.util.Result;
import cn.kgc.util.ResultConstant;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author wangyue
 * @version 1.0
 */
@ControllerAdvice("cn.kgc.controller")
public class ExceptionAdvice {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<Result<Object>> handleMethodException2(MethodArgumentNotValidException exception) {
        BindingResult bindingResult = exception.getBindingResult();
        List<FieldError> fieldErrors = bindingResult.getFieldErrors();
        Map<String, String> errorResult = new HashMap<>();
        for (FieldError fieldError : fieldErrors) {
            String fieldName = fieldError.getField();
            String filedErrorMsg = fieldError.getDefaultMessage();
            errorResult.put(fieldName, filedErrorMsg);
        }
        Result<Object> result = Result.error(exception, errorResult);
        return getResponseEntity(result);
    }

    @ExceptionHandler(ConstraintViolationException.class)
    public ResponseEntity<Result<Object>> handleConstraintViolation(ConstraintViolationException ex) {
        Map<String, String> errors = new HashMap<>();
        for (ConstraintViolation<?> violation : ex.getConstraintViolations()) {
            String field = violation.getPropertyPath().toString().split("\\.")[1];
            errors.put(field, violation.getMessage());
        }
        return getResponseEntity(Result.error(ex, errors));
    }

    @ExceptionHandler(HttpException.class)
    public ResponseEntity<Result<Object>> handleHttpException(HttpException httpException) {
        return getResponseEntity(Result.error(httpException));
    }

    @ExceptionHandler(AccessDeniedException.class)
    public ResponseEntity<Result<Object>> handleAccessDeniedException(AccessDeniedException exception) {
        return getResponseEntity(Result.error(new HttpException(ResultConstant.ACCESS_DENIED)));
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<Result<Object>> handlExcpetion(Exception exception) {
        return getResponseEntity(Result.error(exception));
    }

    private ResponseEntity<Result<Object>> getResponseEntity(Result<Object> result) {
        HttpStatus httpStatus = HttpStatus.OK;
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
        return new ResponseEntity<>(result, httpHeaders, httpStatus);
    }
}